package edu.ubb.remeye.logging.aspect;

import org.apache.mina.core.session.IoSession;

import edu.ubb.remeye.client.communication.handler.ClientStateHandler.ClientContext;
import edu.ubb.remeye.client.settings.ClientSetter;
import edu.ubb.remeye.communication.message.Message;
import edu.ubb.remeye.encodings.EncodingType;
import edu.ubb.remeye.exception.DESSecurityException;
import edu.ubb.remeye.exception.ImageDecodingException;
import edu.ubb.remeye.exception.SettingsLoadingException;
import edu.ubb.remeye.exception.SettingsSavingException;
import edu.ubb.remeye.logging.RemEyeLogger;
import edu.ubb.remeye.security.ResultType;
import edu.ubb.remeye.security.SecurityType;

/**
 * Client logging aspect.
 * 
 * @author Andrew Ianicicau
 *
 */
public aspect ClientLogging {

	///////////////////////////////////////////////////////////////////////////////////
	////		ATTRIBUTES - ClientLogging
	///////////////////////////////////////////////////////////////////////////////////

	/**
	 * Client id.
	 */
	private long clientId;
	
	

	///////////////////////////////////////////////////////////////////////////////////
	////		METHODS - ClientLogging
	///////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Client starting pointcut.
	 */
	private pointcut clientStarted():
		withincode(* edu.ubb.remeye.client.Client.connectClient()) && set(boolean *.clientRunning);
	
	/**
	 * Client starting logging advice.
	 */
	after(): clientStarted() {
		int port = ClientSetter.getInstance().getPort();
		String address = ClientSetter.getInstance().getIp();
		RemEyeLogger.info(null, "CLIENT[STARTING]: started" );
		RemEyeLogger.info(null, "CLIENT[RUNNING]: connected to address " + address + ":" + port);
	}
	
	/**
	 * Client stopping pointcut.
	 */
	private pointcut clientStopped():
		withincode(* edu.ubb.remeye.client.Client.disconnectClient()) && set(boolean *.clientRunning);
	
	/**
	 * Client stopping logging advice.
	 */
	after(): clientStopped() {
		RemEyeLogger.info(null, "CLIENT[STOPPING]: stopped");
	}
	
	/**
	 * Session is opened pointcut.
	 */
	private pointcut sessionOpened():
		execution(void *.sessionOpened(ClientContext, IoSession)) && within(edu.ubb.remeye.client.communication.handler.ClientStateHandler);
	
	/**
	 * Session is opened logging advice.
	 * @param context Client state context.
	 * @param session Client session.
	 */
	after(ClientContext context, IoSession session): sessionOpened() && args(context, session) {
		RemEyeLogger.info(null, "CLIENT[SESSION OPENING]: session opened");
	}
	
	/**
	 * Session is closed pointcut.
	 */
	private pointcut sessionClosed():
		execution(void *.sessionClosed(ClientContext, IoSession)) && within(edu.ubb.remeye.client.communication.handler.ClientStateHandler);
	
	/**
	 * Session is closed logging advice.
	 * @param context Client state context.
	 * @param session Client session.
	 */
	after(ClientContext context, IoSession session): sessionClosed() && args(context, session) {
		RemEyeLogger.info(null, "CLIENT[SESSION CLOSING][CLIENT ID = " + clientId + "]: session closed");
	}
	
	/**
	 * Session timeout pointcut.
	 */
	private pointcut timeout():
		execution(* *.timeout(..)) && within(edu.ubb.remeye.client.communication.handler.ClientStateHandler);
	
	/**
	 * Session timeout logging advice.
	 */
	after(): timeout() {
		RemEyeLogger.info(null, "CLIENT[SESSION TIMEOUT][CLIENT ID = " + clientId + "]: no activity caused session timeout");
	}
	
	/**
	 * Setting identity pointcut.
	 */
	private pointcut settingIdentity():
		withincode(void *.setIdentity(..)) && call(void *.setClientId(long));
	
	/**
	 * Setting identity logging advice.
	 * @param id Id of client.
	 */
	after(long id): settingIdentity() && args(id) {
		clientId = id;
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: identified with ID = " + id);
	}
	
	/**
	 * Setting security type pointcut.
	 */
	private pointcut securitySet():
		execution(* *.setSecurity(ClientContext, IoSession, Message)) && within(edu.ubb.remeye.client.communication.handler.ClientStateHandler);
	
	/**
	 * Setting security type logging advice.
	 * @param context
	 * @param session
	 * @param message
	 */
	after(ClientContext context, IoSession session, Message message): securitySet() && args(context, session, message) {
		SecurityType type = context.getSecurity();
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: security set to " + type);
	}
	
	/**
	 * Starting authentication pointcut.
	 */
	private pointcut authenticationStarted():
		within(edu.ubb.remeye.client.communication.handler.ClientStateHandler) && call(void *.startAuthentication(ClientContext, IoSession));
	
	/**
	 * Starting authentication logging advice.
	 * @param context
	 * @param session
	 */
	after(ClientContext context, IoSession session): authenticationStarted() && args(context, session) {
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: authentication started");
	}
	
	/**
	 * Getting authentication pointcut.
	 */
	private pointcut authenticationResult():
		call(boolean *.getAuthenticationResult(Message));
	
	/**
	 * Getting authentication logging advice.
	 * @param result Result of authentication.
	 */
	after() returning(boolean result): authenticationResult() {
		ResultType res;
		if(result)
			res = ResultType.SUCCEEDED;
		else
			res = ResultType.FAILED;
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: authentication " + res);
	}
	
	/**
	 * Setting encoding pointcut.
	 */
	private pointcut setEncoding():
		withincode(* *.setEncodingResult(..));
	
	/**
	 * Setting encoding logging advice.
	 * @param selected Selected encoding type.
	 */
	after() returning(EncodingType selected): setEncoding() {
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: encoding set to " + selected);
	}
	
	/**
	 * Getting control result pointcut.
	 */
	private pointcut setControl():
		withincode(* *.controlRequestResult(..));
	
	/**
	 * Getting control result logging advice.
	 * @param message
	 * @param context
	 * @param control
	 */
	after(Message message, ClientContext context) returning (boolean control): setControl() && args(message, context) {
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: in control of server: " + control);
	}
	
	/**
	 * Desktop is shared pointcut.
	 */
	private pointcut shared():
		execution(* *.controlRequestResult(..));
	
	/**
	 * Desktop is shared logging advice.
	 * @param context
	 * @param session
	 * @param message
	 */
	after(ClientContext context, IoSession session, Message message) returning(): shared() && args(context, session, message) {
		RemEyeLogger.info(null, "CLIENT[SESSION RUNNING][CLIENT ID = " + clientId + "]: desktop shared by server");
	}
	
	/**
	 * ImageDecodingException is thrown logging advice.	
	 * @param e
	 */
	before(ImageDecodingException e): handler(ImageDecodingException) && args(e) {
		RemEyeLogger.error(null, "CLIENT[SESSION ERROR]: " + e.getMessage());
	}
	
	/**
	 * SettingsLoadingException is thrown logging advice.	
	 * @param e
	 */
	before(SettingsLoadingException e): handler(SettingsLoadingException) && args(e) && within(edu.ubb.remeye.client.settings.ClientSetter){
		RemEyeLogger.error(null, "CLIENT[SESSION ERROR]: " + e.getMessage());
	}
	
	/**
	 * SettingsSavingException is thrown logging advice.	
	 * @param e
	 */
	before(SettingsSavingException e): handler(SettingsSavingException) && args(e) && within(edu.ubb.remeye.client.settings.ClientSetter){
		RemEyeLogger.error(null, "CLIENT[SESSION ERROR]: " + e.getMessage());
	}
	
	/**
	 * DESSecurityException is thrown logging advice.	
	 * @param e
	 */
	before(DESSecurityException e): handler(DESSecurityException) && args(e) && within(edu.ubb.remeye.security.manager.vnc.ClientVNCAuthenticator){
		RemEyeLogger.error(null, "CLIENT[SESSION ERROR]: " + e.getMessage());
	}
	
}
